﻿using System;
using System.Collections.Generic;
using System.Linq;
using KamLib;

namespace KamLib
{

    public class UilController : IDisposable
    {
        public UilControllerTypeInfo TypeInfo { get; internal set; }
        public UilContext Context { get; internal set; }
        public UilKey Key { get; set; }


        /// <summary>
        /// Initializes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Initialize(UilContext context)
        {
            Context = context;
        }

        public virtual void Dispose()
        {
        }

        public override string ToString()
        {
            return GetType().Name + (Key != null ? " " + Key.CTID : null);
        }


        #region Actions

        /// <summary>
        /// Возвращает Actions по списку имён.
        /// </summary>
        public IEnumerable<UilAction> GetActions(IUilViewPart part, params string[] mids)
        {
            foreach (var mid in mids)
            {
                var method = TypeInfo.Methods.Try(mid);
                if (method == null) continue;
                var action = method.AsAction(this, part);
                if (action == null) continue;
                yield return action;
            }
        }

        /// <summary>
        /// Возвращает все Actions.
        /// </summary>
        public IEnumerable<UilAction> GetAllActions(IUilViewPart part)
        {
            return TypeInfo.Methods.Values.Select(a => a.AsAction(this, part)).Where(a => a != null).ToArray();
        }

        /// <summary>
        /// Возвращает Actions в зависимости от part (его Name).
        /// </summary>
        /// <param name="part">The part.</param>
        /// <returns></returns>
        public IEnumerable<UilAction> GetActions(IUilViewPart part)
        {
            return GetAllActions(part);
        }

        #endregion


        #region Methods

        /// <summary>
        /// Gets the method.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <returns></returns>
        public IUilMethod GetMethod(UilMethodArgs e)
        {
            var method = FindMethod(e);
            if (method == null)
                throw new Exception("UilController.GetMethod()\r\n Can't find method '" + e.MethodAlias + "' in controller '" + ToString() + "'.");
            return method;
        }

        /// <summary>
        /// Gets the method.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <returns></returns>
        public virtual IUilMethod FindMethod(UilMethodArgs e)
        {
            return TypeInfo.Methods.Try(e.MethodAlias);
        }

        #endregion


        #region Parts

        /// <summary>
        /// Должен возвращать controller для part (по его имени)
        /// </summary>
        public virtual UilController GetPartController(IUilViewPart viewPart)
        {
            return null;
        }

        #endregion


        #region Views

        public void InitView(IUilView view)
        {
            view.Controller = this;
            InitViewParts(view);
        }


        /// <summary>
        /// Именно здесь part-controllers прикручиваются к view parts
        /// </summary>
        protected void InitViewParts(IUilView view)
        {
            var parts = view.Parts;
            if (parts == null) return;

            foreach (var part in parts)
            {
                if (part.Controller == null)
                {
                    UilController partCtrl = null;
                    var ctrl = view.Controller;
                    if (ctrl != null)
                        partCtrl = ctrl.GetPartController(part);

                    part.Controller = partCtrl ?? GetPartController(part);
                }

                InitViewParts(part);
            }
        }


        public IUilView NewView(string vtid = null)
        {
            return Context.NewView(this, vtid);
        }

        #endregion
    }
}